const axios = require('axios')
const webpack = require('webpack')
const path = require('path')
const MemoryFs = require('memory-fs')
const proxy = require('http-proxy-middleware')

const serverRender = require('./server.render')

const serverConfig = require('../../build/webpack.config.server')

// 获取实时的template.html
const getTemplate = () => {
  return new Promise((resolve, reject) => {
    axios.get('http://localhost:8888/public/server.ejs')
      .then(res => {
        resolve(res.data)
      })
      .catch(reject)
  })
}

// 这个是 module.exports 的module
const NativeModule = require('module')
const vm = require('vm')

const getModuleFromString = (bundle, filename) => {
  const m = { exports: {} }
  // NativeModule.wrap可以帮我们包装一段代码
  // 包装成 `(function(exports, require, module, __filename, __dirname) { ...bundle code })的字符串`
  const wrapper = NativeModule.wrap(bundle)
  // 通过vm.Script把字符串变成可执行的代码
  const script = new vm.Script(wrapper, {
    filename: filename,
    displayErrors: true
  })
  // 指定script的执行环境
  const result = script.runInThisContext()
  // 让m.exports去当执行者,执行result, m.exports就是我们传过去的第一个参数exports, require就是第二个参数require, m就是第三个参数module
  result.call(m.exports, m.exports, require, m)
  return m
}

const mfs = new MemoryFs()

let serverBundle

// 获取实时webpack的打包信息,实现当bundle改变时,自动改变页面内容，而不需要我们重新启动服务
const serverCompiler = webpack(serverConfig)
serverCompiler.outputFileSystem = mfs
serverCompiler.watch({}, (err, stats) => {
  if (err) {
    throw err
  }
  stats = stats.toJson()
  stats.errors.forEach(err => console.error(err))
  stats.warnings.forEach(warn => console.warn(warn))

  const bundlePath = path.join(
    serverConfig.output.path,
    serverConfig.output.filename
  )

  // 该bundle类型是stream
  const bundle = mfs.readFileSync(bundlePath, 'utf-8')

  // 通过构造模块转换stream
  // const m = new Module()
  // 内存里也要指定文件名字
  // m._compile(bundle, 'server-entry.js')

  const m = getModuleFromString(bundle, 'server-entry.js')
  serverBundle = m.exports
})

module.exports = function (app) {
  app.use('/public', proxy({
    target: 'http://localhost:8888'
  }))

  app.get('*', function (req, res, next) {
    // 只会在开发的时候出现的问题
    if (!serverBundle) {
      return res.send('webpack正在执行,请稍后重新刷新页面')
    }

    getTemplate().then(template => {
      return serverRender(serverBundle, template, req, res)
    }).catch(next)
  })
}
